#!/bin/bash

##########################################
# Copyrights 2020, Wizcas <chen@0x1c.dev>
#
# This script is under MIT license
##########################################

#----------- 辅助工具 -----------
####### 颜色码 ########
RED="\033[31m"     # Error message
GREEN="\033[32m"   # Success message
YELLOW="\033[33m"  # Warning message
BLUE="\033[34m"    # Info message
MAGENTA="\033[35m" # Info message
TEAL="\033[36m"    # Info message
RAW="\033[0m"

colorEcho() {
  echo -e "${1}${@:2}${RAW}" 1>&2
}
##########################

# 一些预定义常量
VERSION='0.2.0'
conf="${HOME}/.wsl2proxy.conf"
socks="${HOME}/socksproxy"
varsfile="${HOME}/wsl2proxy.vars"
cmd="wsl2proxy"

# 从WSL的DNS配置中解析当前Windows主机的访问IP，因为每次重启都会变
host=$(cat /etc/resolv.conf | sed -n 's/^nameserver\W\(.*\)$/\1/p')

# 让用户选择代理用什么协议
selectProtocol() {
  echo -e "\n${YELLOW}[STEP 1]${BLUE} 代理协议: ${RAW}\n---- 请选择数字 ----"
  PROTOCOLS=("http" "https" "socks5" "socks4")
  PS3="-----------------
Protocol > "
  select protocol in ${PROTOCOLS[@]}; do
    case $protocol in
    "http" | "https")
      ncProtocol="connect"
      break
      ;;
    "socks5")
      ncProtocol=5
      break
      ;;
    "socks4")
      ncProtocol=4
      break
      ;;
    *)
      colorEcho ${RED} "请选择一个从1到${#PROTOCOLS[@]}的数字"
      ;;
    esac
  done
}

# Let user input the proxy server port
inputPort() {
  echo -e "\n${YELLOW}[STEP 2]${BLUE} 代理端口: ${RAW}"
  while true; do
    read -p "Port > " port
    if [ -z ${port} ]; then
      colorEcho ${RED} "你的代理总得有个端口吧？😒"
    else
      if [[ ${port} =~ ^[1-9][0-9]+$ ]] && [[ ${port} -le 65535 ]]; then
        break
      else
        colorEcho ${RED} "无效的端口号"
      fi
    fi
  done
}

# Save configs into a conf file
saveConf() {
  echo "# This file is for storaging WSL proxy settings.
# The host IP is not recorded since it changes every time on reboot.

protocol=${protocol}
ncProtocol=${ncProtocol}
port=${port}
  " >${conf}

  colorEcho ${GREEN} "
代理配置已成功存储到 ${YELLOW}${conf}${GREEN}, 请不要删除。
"
}

# Since SSH proxy depends on `nc` tool for forwarding,
# this function checks the prerequisite
checkNc() {
  command -v nc >/dev/null
  nc=$?
  if [ $nc -ne 0 ]; then
    colorEcho ${RED} "警告: 未找到命令${YELLOW}nc${RED}。SSH代理需要使用该命令，请自行安装。"
  fi
}

# Create a utility for calling nc to forward network traffics
setupSocksProxy() {
  updateSocksProxy

  echo -e "\
-------------
${RED}[需要手动设置]${RAW}

已创建网络请求转发脚本${YELLOW}${socks}${RAW}，
请进行如下配置，以便正常使用SSH代理与git通信：

1) 新建或编辑文件${YELLOW}~/.ssh/config\e${RAW}，并写入类似下面的内容：
   (你可能需要首先给该文件可写权限)
${TEAL}
Host github.com
    User git
    ProxyCommand ${socks} '%h %p'
${RAW}
2) 重新给${YELLOW}~/.ssh/config${RAW}文件一个只读权限，以通过SSH安全检查
${TEAL}
chmod 400 ~/.ssh/config
${RAW}
-------------"
}

updateSocksProxy() {
  # Makes the proxy command
  echo "#!/bin/bash
nc -x ${host}:${port} -X ${ncProtocol} \$*
" >${socks}
  chmod +x ${socks}
}

# The `setup` command's handler
setup() {
  selectProtocol
  inputPort
  echo -e "你的代理服务器是: ${TEAL}${protocol}://${host}:${port}${RAW}"
  echo
  while true; do
    read -p "地址是否正确? (Y/n): " CONFIRMED
    case $CONFIRMED in
    "y" | "Y" | "")
      break
      ;;
    "n" | "N")
      colorEcho ${BLUE} "👋🏻️ 再见"
      exit 2
      ;;
    *)
      colorEcho ${RED} "啥？"
      ;;
    esac
  done

  saveConf
  checkNc
  setupSocksProxy

  colorEcho ${RED} "<<< 随WSL启动自动开启代理 >>>"
  echo -e "${TEAL}注意: ${RAW}本工具的代理设置会应用到
${YELLOW}http_proxy, https_proxy${RAW}和${YELLOW}.gitconfig${RAW}上

若需随WSL启动自动开启代理，请将下面这行代码添加到${YELLOW}$(getProfile)${RAW}中
(注意不要遗漏命令开头的‘.’)：

    ${TEAL}. ${cmd} on${RAW}
"
}

# Load proxy settings from our config file. Throws an error message if not found.
loadConf() {
  if [ ! -f "${conf}" ]; then
    colorEcho ${RED} "
未找到配置文件${TEAL}${conf}${RED}，请首先执行${YELLOW}setup${RED}命令。

${RAW}用法:    ${cmd} setup"
    exit 1
  fi
  . "${conf}"
  url="${protocol}://${host}:${port}"
}

# Determine what's the shell's profile script
getProfile() {
  if [ -n "$($SHELL -c 'echo $ZSH_VERSION')" ]; then
    # assume Zsh
    echo '.zshrc'
  elif [ -n "$($SHELL -c 'echo $BASH_VERSION')" ]; then
    # assume Bash
    echo '.bashrc'
  else
    # assume something else
    echo "shell启动脚本"
  fi
}

# The `on` command's handler
on() {
  loadConf
  echo -e "正在配置代理服务器 ${YELLOW}${url}${RAW}"
  export http_proxy=${url}
  export https_proxy=${url}
  applyGit ${url}
  applyKde ${host} ${port}
  applyFirefox ${host} ${port}
  updateSocksProxy
}

# Set the proxy settings for git
applyGit() {
  # For HTTP/HTTPS protocol
  git config --global http.proxy $1
  git config --global https.proxy $1
  # For git:// protocol
  git config --global core.gitproxy ${socks}
  echo "✔️️ git设置完毕"
}

# Set the proxy settings for KDE 5
# See https://stackoverflow.com/questions/48137501/how-to-setup-network-proxy-in-kde-desktop-system
applyKde() {
  kwriteconfig5 --file kioslaverc --group 'Proxy Settings' --key ProxyType "1"
  kwriteconfig5 --file kioslaverc --group 'Proxy Settings' --key Authmode 0
  kwriteconfig5 --file kioslaverc --group 'Proxy Settings' --key httpProxy "$1:$2"
  kwriteconfig5 --file kioslaverc --group 'Proxy Settings' --key httpsProxy "$1:$2"
  kwriteconfig5 --file kioslaverc --group 'Proxy Settings' --key ftpProxy "ftp:$2"
  kwriteconfig5 --file kioslaverc --group 'Proxy Settings' --key socksProxy "socks:$2"
  dbus-send --type=signal /KIO/Scheduler org.kde.KIO.Scheduler.reparseSlaveConfiguration string:''
}

# Set the proxy settings for Firefox
# See http://kb.mozillazine.org/User.js_file#About_the_user.js_file
# See http://kb.mozillazine.org/User.js_file#About_the_user.js_file
applyFirefox() {
  for i in $HOME/.mozilla/firefox/*default*
  do
    echo -e "user_pref('network.proxy.type', 1);\nuser_pref('network.proxy.http', $1);\nuser_pref('network.proxy.http_port', $2);\n" > "$i/user.js"
  done
}

# Unset all proxy settings
off() {
  unset http_proxy
  unset https_proxy
  echo "👋🏻️ 已删除系统变量"
  git config --global --unset http.proxy
  git config --global --unset https.proxy
  git config --global --unset core.gitproxy
  echo "👋🏻️ 已删除git配置"
  kwriteconfig5 --file kioslaverc --group "Proxy Settings" --key "ProxyType" 0
  echo "👋🏻️ 已删除kde配置"
  for i in $HOME/.mozilla/firefox/*default*
  do
    echo -e "user_pref('network.proxy.type', 0);\n" > "$i/user.js"
  done
  echo "👋🏻️ 已删除firefox配置"
  colorEcho ${RED} "
如果不再使用代理服务器，别忘了:
${RAW}
1.  删除或注释掉${YELLOW}$(getProfile)${RAW}中 wsl2proxy 相关的部分
2.  删除或注释掉${YELLOW}~/.ssh/config${RAW}中的代理设置
"
}

# Print the help info
help() {
  echo -e "
WSL代理服务器配置工具

    - authored by Wizcas <chen@0x1c.dev>

本工具自动检测WSL的Windows主机地址，并使用自定义的代理信息为
HTTP，HTTPS和Git添加代理配置。

Usage:
  ${cmd} <COMMAND>

Commands:
  install  将脚本安装到 /usr/local/bin
  setup    设置代理参数 (协议、端口等) ，并创建socks代理
           转发脚本
  on       开启代理设置，只有使用setup正常配置后才能生效。
           执行方式：${TEAL}. ${cmd} on${RAW}
  off      关闭代理设置。
           执行方式：${TEAL}. ${cmd} off${RAW}
  url      打印当前的代理服务器地址
  help     显示本帮助信息
  version  显示脚本版本
"
}

# installs the script to /usr/local/bin
install() {
  if [ "$EUID" -ne 0 ]; then
    colorEcho ${RED} "
请使用root权限执行脚本，如：

    ${RAW}sudo $0 install
"
    exit 1
  fi
  exePath="/usr/local/bin/${cmd}"
  cp -f $(realpath $0) ${exePath}
  chmod +x ${exePath}
  echo "✔️️ 安装完成。现在可以用如下命令配置代理:

    ${cmd} setup
  "
}

# Main entry of the bash script
case $1 in
install)
  install
  ;;
setup)
  setup
  ;;
off)
  off
  ;;
on)
  on
  ;;
url)
  loadConf
  echo ${url}
  ;;
version)
  echo WSL2Proxy: ${VERSION}
  ;;
*)
  help
  ;;
esac
